/**
 * @file nb_comp.h
 * @brief
 *
 * @version 0.1
 * @date 2023-09-06
 *
 * @copyright  Copyright (c) 2020~2030 ShenZhen dingxintongchuang Technology Co., Ltd.
 * All rights reserved.
 *
 * @note          鼎新同创・智能锁
 *
 * @par 修改日志:
 * <1> 2023-09-06 v0.1 tianshidong 创建初始版本
 * *************************************************************************
 */
#ifndef __NB_COMP_H__
#define __NB_COMP_H__
#include "osal.h"

#define TEST_NB_RF (0)                            //调试NB模组天线时打开此宏，此时不会进入PSM模式，不会休眠
#define CTM2MREAD_MODE_USED_1 1                   //设置平台数据读取模式
#define NB_POWER_ON_DELAY_TIME (3000)             //上电后3s，给NB发送开机指令
#define NB_NORMAL_CMD_RESEND_TIMES (3)            //无特殊要求的AT指令重发次数
#define NB_NORMAL_CMD_RESEND_INTERVAL (300)       //无特殊要求的AT指令重发间隔
#define NB_SEND_BUFFER_SIZE (512)                 //
#define NB_CONTROL_IO_DOWN_TIMEROUT (1100)        //唤醒或复位IO口拉低的时间
#define NB_RUN_STATUS_CHECK_TIMEOUT (1000)        //
#define NB_DECRYPTION_FRAME_TYPE_START (0x5B)     //加密帧格式
#define NB_NOT_DECRYPTION_FRAME_TYPE_START (0x5A) //非加密帧格式
#define NB_DECRYPTION_FRAME_TYPE_END (0xB5)       //加密帧格式
#define NB_NOT_DECRYPTION_FRAME_TYPE_END (0xA5)   //非加密帧格式
/**
 *
 * @brief 初始化流程所需AT指令
 *
 *
 * @note 初始化状态
 */
#define NWY_AT_CMD_AT "AT"                        //开机
#define NWY_AT_CMD_CGSN "AT+CGSN=1"               //获取产品IMEI
#define NWY_AT_CMD_CGMR "AT+CGMR"                 //获取厂商版本号
#define NWY_AT_CMD_CPIN "AT+CPIN?"                //检查SIM卡状态
#define NWY_AT_CMD_CIMI "AT+CIMI"                 //获取卡IMSI
#define NWY_AT_CMD_ICCID "AT+ECICCID"             //获取卡ICCID
#define NWY_AT_CMD_CSQ "AT+CSQ"                   //获取信号强度
#define NWY_AT_CMD_CGATT "AT+CGATT?"              //查询网络附着情况
#define NWY_AT_CMD_CEREG "AT+CEREG?"              //查询网络注册情况
#define NWY_AT_CMD_CCLK "AT+CCLK?"                //获取时间
#define NWY_AT_CMD_ECSTATUS_RRC "AT+ECSTATUS=RRC" //返回 UE 端关键参数状态
#define NWY_AT_CMD_ECSTATUS_PHY "AT+ECSTATUS=PHY" //返回 UE 端关键参数状态
#define NWY_AT_CMD_ECBCINFO "AT+ECBCINFO"         //返回服务小区和邻区信息
#define NWY_AT_CMD_RESET "AT+ECRST"               //重启NB模组
#define NWY_AT_CMD_CMEE "AT+CMEE=1"               //设置上报 MT 错
// #define NWY_AT_CMD_ATE_CLOSE "AT+ECPCFG=\"logCtrl\",2" //打开LOGO
#define NWY_AT_CMD_ATE_CLOSE "ATE0"       //关闭回显
#define NWY_AT_CMD_ATE_OPEN "ATE1"        //打开回显
#define USER_CMD_TIMEOUT "TIMEOUT"        //命令执行超时
#define NWY_AEP_STATUS_NOT_LOGIN '0'      //未登录
#define NWY_AEP_STATUS_ALREADY_LOGIN '1'  //已登录
#define NWY_AEP_STATUS_LOADING_LOGIN '2'  //正在登录中
#define NWY_AEP_STATUS_HANGUP '3'         //挂起
#define NWY_AEP_STATUS_LOADING_LOGOUT '4' //登出中
#define NWY_AEP_STATUS_ALREADY_LOGOUT '5' //已登出

/**
 * @brief 注册平台所需AT（需要先跑完初始化流程）
 *
 *
 * @note
 */
#define NWY_AT_CMD_CGPADDR "AT+CGPADDR"                                 //查询IP地址
#define NWY_AT_CMD_CTM2MSETPM "AT+CTM2MSETPM=221.229.214.202,5683,3600" //设置电信AEP平台地址和端口
#define NWY_AT_CMD_CTM2MREG "AT+CTM2MREG"                               //登录AEP平台
#define NWY_AT_CMD_INQUIRY_CTM2MREG "AT+CTM2MREG?"                      //查询平台登录状态
#define NWY_AT_CMD_CTM2MDEREG "AT+CTM2MDEREG"                           //发送注销请求
#if CTM2MREAD_MODE_USED_1
#define NWY_AT_CMD_CTM2MRMODE "AT+CTM2MRMODE=1"   //设置平台数据读取模式1
#else                                             //
#define NWY_AT_CMD_CTM2MRMODE "AT+CTM2MRMODE=2"   //设置平台数据读取模式2
#endif                                            //
#define NWY_AT_CMD_CTM2MREAD "AT+CTM2MREAD"       //读取平台缓存数据
#define NWY_AT_CMD_CTM2MSEND_HEAD "AT+CTM2MSEND=" //发送数据到平台，此命令头+数据（字符串格式）

#define NWY_AT_CMD_SEND_DATA_TEST "AT+CTM2MSEND=030D05"
#define NWY_AT_CMD_SEND_ATE_DATA "S2MACK="
/**
 * @brief PSM低功耗模式所需指令
 *
 *
 * @note
 */
#define NWY_AT_CMD_CPSMS "AT+CPSMS=1"                    //使能低功耗模式
#define NWY_AT_CMD_PSM_CLOSE "AT+ECPMUCFG=1,1"           //关闭低功耗模式
#define NWY_AT_CMD_PSM_OPEN "AT+ECPMUCFG=1,4"            //开启低功耗模式
#define NWY_AT_CMD_ECCFG "AT+ECCFG=\"T3324MaxValueS\",2" //设置3324定时器时间，重启生效
#define NWY_AT_CMD_ECNBIOTRAI "AT+ECNBIOTRAI=1"          //释放RCC连接
#define NWY_AT_CMD_ECPURC "AT+ECPURC=\"HIBNATE\",1"      //设置模块 进入/退出 低功耗模式后，都打印信息

#define NWY_AT_CMD_ECVOTECHK "AT+ECVOTECHK" //任务投票状态（仅调试）

/**
 * @brief 消息码
 *
 *
 * @note
 */
#define CMD_EXECUTE_SUCCESS 0X00 //下行指令执行成功
#define CMD_EXECUTE_FAILED 0X01  //下行指令执行失败
#define CMD_TYPE_REPORT 0X02     //门锁主动上报类数据
#define CMD_TYPE_DOWN 0X03       //下行类数据

#pragma pack(1)

typedef enum
{
    NB_CONTROL_ENTER_PSM = 0x01,         //控制模组进入PSM
    NB_CONTROL_EXIT_PSM = 0x02,          //控制模组退出PSM
    NB_CONTROL_RESET = 0x03,             //控制模组复位
    NB_CONTROL_ENTER_PSM_NOT_RAI = 0x04, //控制模组进入PSM 无需先释放RCC
} NB_control_status_enum_t;
typedef enum
{
    NB_STATUS_INIT = 0,      //刚上电，需要初始化的状态
    NB_STATUS_RESET,         //复位
    NB_STATUS_RUNNING,       //初始化完成的状态
    NB_STATUS_CONNECTED_AEP, //连接AEP平台后的状态
    NB_STATUS_WAITPSM,       //等待进入PSM低功耗状态
    NB_STATUS_PSM,           //已进入PSM低功耗状态
} NB_runStatus_enum_t;

typedef enum
{
    CURRENT_SEND_INVALID = 0,      /* 初始化状态无效指令 */
                                   //
    CURRENT_SEND_AT,               /* 开机指令，建议上电后3s后发送 */
    CURRENT_SEND_CGSN,             /* 查询IMEI号指令 */
    CURRENT_SEND_CGMR,             /* 查询NB模组版本号 */
    CURRENT_SEND_CPIN,             /* 检查SIM卡状态 */
    CURRENT_SEND_CIMI,             /* 获取卡IMSI */
    CURRENT_SEND_ICCID,            /* 获取卡ICCID */
    CURRENT_SEND_CSQ,              /* 获取信号强度 */
    CURRENT_SEND_CGATT,            /* 查询网络附着情况 */
    CURRENT_SEND_CEREG,            /* 查询网络注册情况 */
    CURRENT_SEND_CCLK,             /* 获取NB时间 */
    CURRENT_SEND_ECBCINFO,         /* 返回服务小区和邻区信息 */
    CURRENT_SEND_ECSTATUS_RRC,     /* 返回 UE 端关键参数状态 RRC*/
    CURRENT_SEND_ECSTATUS_PHY,     /* 返回 UE 端关键参数状态 phy*/
    CURRENT_SEND_RESET,            /* 复位模组指令，最大响应时间5s */
                                   //
    CURRENT_SEND_ATE_CLOSE,        /* 关闭 回显指令 */
    CURRENT_SEND_ATE_OPEN,         /* 开启 回显指令 */
                                   //
    CURRENT_SEND_CGPADDR,          /* 查询IP地址 */
    CURRENT_SEND_CTM2MSETPM,       /* 设置电信AEP平台地址和端口 */
    CURRENT_SEND_INQUIRY_CTM2MREG, /* 查询AEP平台登录状态 */
    CURRENT_SEND_CTM2MREG,         /* 登录AEP平台 */
    CURRENT_SEND_CTM2MRMODE,       /* 设置平台数据读取模式 */
    CURRENT_SEND_CTM2MREAD,        /* 读取平台缓存数据 */
    CURRENT_SEND_CTM2MSEND,        /* 发送数据到平台 */
    CURRENT_SEND_CTM2MDEREG,       /* 注销平台请求 */
                                   //
    CURRENT_SEND_CPSMS,            /* 使能低功耗模式 */
    CURRENT_SEND_PSM_CLOSE,        /* 关闭低功耗模式 */
    CURRENT_SEND_PSM_OPEN,         /* 开启低功耗模式 */
    CURRENT_SEND_ECCFG,            /* 设置3324定时器时间，重启生效 */
    CURRENT_SEND_ECNBIOTRAI,       /* 释放RRC连接 */
    CURRENT_SEND_ECPURC,           /* 进入或者退出 PSM模式， log信息上报 */
    CURRENT_SEND_STOP_INTOPSM,     /* 中止进入功耗 */
    CURRENT_SEND_ECVOTECHK,        /* 查询任务投票状态，分析睡眠失败的原因 */
                                   //
    CURRENT_SEND_TEST,             /* 退出低功耗，需要先发送数据给AEP，然后再读取数据 */
    CURRENT_SEND_ATE,              /* 产测数据*/
    CURRENT_SEND_CMEE,             /* 设置上报 MT 错 */
    CURRENT_SEND_MAX_STATUS,
} NB_cmdCurSendStatus_enum_t;

/* NB UE关键状态参数 */
typedef struct
{
    uint8_t dlEarfcn[6]; //下行频点, 取值范围 0~262143
    uint8_t dlEarfcnLen; //字符串长度
    uint8_t pci[3];      // 物理 CELL ID，取值范围 0~503
    uint8_t pciLen;      //字符串长度
    uint8_t rsrp[4];     //单位是 dBm，取值范围-156dBm ~ -44dBm
    uint8_t rsrpLen;     //
    uint8_t snr[3];      //单位是 dB，取值范围-30dB ~ 30dB
    uint8_t snrLen;      //
    uint8_t txPower[4];  //当前 TX 发射功率， dBm 为单位取值范围-45~23.-128 代表无效值
    uint8_t txPowerLen;  //
    uint8_t cellId[9];   //整型，取值范围 0~268435455
    uint8_t cellIdLen;   //
} Nb_ueImportantPara_t;

/* 蓝牙PUBLISH消息（COMP->应用层）*/
typedef struct
{
    uint8_t type;    //上报的类型
    uint16_t MID;    //云平台下发，ack时需填入
    uint8_t SID;     // 唯一标识
    uint16_t len;    // 数据长度
    uint8_t pData[]; // 数据(cmd+data)
} NbPublishMsg_t;

/* 蓝牙应用层下发消息（应用层->COMP）*/
typedef struct
{
    uint16_t MID;                       //云平台下发，ack时需填入
    uint8_t SID;                        // 唯一标识
    uint16_t len;                       // 数据长度
    uint8_t pData[NB_SEND_BUFFER_SIZE]; // 数据(cmd+data)
} NbSendToLotMsg_t;

typedef struct
{
    uint8_t curSendCmd;      //正在发送的命令字
    uint8_t resendCount;     //命令重发计数
    uint8_t resendTimes;     //命令重发次数
    uint16_t resendInterval; //命令重发间隔
    uint8_t SendStatus;      //发送状态
    uint16_t SendDataLen;    //发送数据长度
    uint32_t TimeStamp;      //发送命令的时间戳
    uint8_t SendBuffer[NB_SEND_BUFFER_SIZE * 2];
} NB_sendManage_stu_t;

/* NB协议格式 */
typedef struct
{
    uint16_t MID;               //云平台下发，ack时需填入
    uint8_t start;              //包头 0x5a明文，0x5B密文
    uint8_t protocolVersion[3]; //协议版本
    uint8_t SID;                //唯一标识
    uint16_t dataLen;           // CMD+DATA长度
    uint8_t mType;              //消息类型
    uint8_t cmd;                //命令字
    uint8_t data[];             //数据
    // uint8_t DCC;                 //XOR校验，从start--data
    // uint8_t end;                 //包尾 0x5a明文，0x5B密文
} NB_protocol_stu_t;

/* NB处理蓝牙转发的协议格式 */
typedef struct
{
    uint16_t MID;               //云平台下发，ack时需填入
    uint8_t start;              //包头 0x5a明文，0x5B密文
    uint8_t protocolVersion[3]; //协议版本
    uint8_t SID;                //唯一标识
    uint16_t dataLen;           // CMD+DATA长度
    uint8_t mType;              //消息类型
    uint8_t cmd;                //命令字
    uint8_t data[];             //数据
    // uint8_t DCC;                 //XOR校验，从start--data
    // uint8_t end;                 //包尾 0x5a明文，0x5B密文
} NB_ble_forward_protocol_stu_t;

typedef struct
{
    uint8_t start;              //包头 0x5a明文，0x5B密文
    uint8_t protocolVersion[3]; //协议版本
    uint8_t SID;                //唯一标识
    uint16_t dataLen;           // CMD+DATA长度
    uint8_t mType;              //消息类型
    uint8_t cmd;                //命令字
    uint8_t data[];             //数据
    // uint8_t DCC;                 //XOR校验，从start--data
    // uint8_t end;                 //包尾 0x5a明文，0x5B密文
} NB_ble_forward_protocol_publish_stu_t;

/* 0x01门锁设置密钥命令 */
typedef struct
{
    uint32_t failureTime; //指令失效时间
    uint8_t key[16];      //密钥
} NB_Set_key_cmd_stu_t;

#pragma pack()

/* NB消息类型（底层往上报的消息类型） */
typedef enum
{
    PUBLISH_APP_IMEI,
    PUBLISH_APP_NB_DATA,
    PUBLISH_APP_CSQ,
    PUBLISH_APP_ICCID,
    PUBLISH_APP_UE,
    PUBLISH_APP_AEP_OTA,
    PUBLISH_APP_ATE,
} NbPublishType_enum_t;

/* NB控制类型（应用层下发的数据类型） */
typedef enum
{
    NB_CTRL_DATA,       //发数据给组件层
    NB_CTRL_PSM_STATUS, //告诉模组读取lot消息
    NB_CTRL_AES_KEY,    //下发给模组初始的AES_KEY
    NB_CTRL_SOUTH_PORT, //下发给模组平台南上地址和端口号
    NB_CTRL_GET_CSQ,    //获取CSQ
    NB_CTRL_AEP_OTA,    //发OTA数据给组件层
    NB_CTRL_ATE,        //下发给模组产测数据
} NbCtrl_enum_t;
#pragma pack(1)
/* AEP OTA应用层下发消息（应用层->COMP）*/
typedef struct
{
    uint8_t cmd;
    uint16_t len;                       // 数据长度
    uint8_t pData[NB_SEND_BUFFER_SIZE]; // 数据(cmd+data)
} NbSendToAepOtaMsg_t;

/* AEP OTA协议格式 */
typedef struct
{
    uint16_t heard;      //包头0XFFFE
    uint8_t specVersion; //版本号 0x01
    uint8_t cmd;         //命令字
    uint16_t crc;        //校验码
    uint16_t dataLen;    // DATA长度
    uint8_t data[];      //数据
} AepOta_protocol_stu_t;
#pragma pack()
/*
 * 发送数据包（应用层->COMP）
 * param：该参数是个结构体指针：
 */
#define Nb_SendDataToNb(str, len)                        \
    ({                                                   \
        uint8_t *temp = (uint8_t *)OSAL_Malloc(len + 1); \
        temp[0] = NB_CTRL_DATA;                          \
        memcpy((char *)&temp[1], str, (len));            \
        OSAL_MboxPost(COMP_NB, 0, temp, (len + 1));      \
        OSAL_Free(temp);                                 \
    })

/*
 * 发送数据包（应用层->COMP）
 * param：该参数是个结构体指针：
 */
#define Nb_SendCmdToNb(str, len)                         \
    ({                                                   \
        uint8_t *temp = (uint8_t *)OSAL_Malloc(len + 1); \
        temp[0] = NB_CTRL_PSM_STATUS;                    \
        memcpy((char *)&temp[1], str, (len));            \
        OSAL_MboxPost(COMP_NB, 0, temp, (len + 1));      \
        OSAL_Free(temp);                                 \
    })
/*
 * 发送数据包（应用层->COMP）
 * param：该参数是个结构体指针：
 */
#define Nb_SendAESToNb(str, len)                         \
    ({                                                   \
        uint8_t *temp = (uint8_t *)OSAL_Malloc(len + 1); \
        temp[0] = NB_CTRL_AES_KEY;                       \
        memcpy((char *)&temp[1], str, (len));            \
        OSAL_MboxPost(COMP_NB, 0, temp, (len + 1));      \
        OSAL_Free(temp);                                 \
    })
/*
 * 发送数据包（应用层->COMP）
 * param：该参数是个结构体指针：
 */
#define Nb_Send_ATE_ToNb(str, len)                       \
    ({                                                   \
        uint8_t *temp = (uint8_t *)OSAL_Malloc(len + 1); \
        temp[0] = NB_CTRL_ATE;                           \
        memcpy((char *)&temp[1], str, (len));            \
        OSAL_MboxPost(COMP_NB, 0, temp, (len + 1));      \
        OSAL_Free(temp);                                 \
    })

/*
 * 发送平台（应用层->COMP）
 * param：该参数是个结构体指针：
 */
#define Nb_SendNetInfoToNb(str, len)                     \
    ({                                                   \
        uint8_t *temp = (uint8_t *)OSAL_Malloc(len + 1); \
        temp[0] = NB_CTRL_SOUTH_PORT;                    \
        memcpy((char *)&temp[1], str, (len));            \
        OSAL_MboxPost(COMP_NB, 0, temp, (len + 1));      \
        OSAL_Free(temp);                                 \
    })

/*
 * 发送平台（应用层->COMP）
 * param：该参数是个结构体指针：
 */
#define Nb_SendReadCsq(str, len)                         \
    ({                                                   \
        uint8_t *temp = (uint8_t *)OSAL_Malloc(len + 1); \
        temp[0] = NB_CTRL_GET_CSQ;                       \
        memcpy((char *)&temp[1], str, (len));            \
        OSAL_MboxPost(COMP_NB, 0, temp, (len + 1));      \
        OSAL_Free(temp);                                 \
    })

/*
 * 发送数据包（应用层->COMP）
 * param：该参数是个结构体指针：
 */
#define Nb_SendAepOtaDataToNb(str, len)                  \
    ({                                                   \
        uint8_t *temp = (uint8_t *)OSAL_Malloc(len + 1); \
        temp[0] = NB_CTRL_AEP_OTA;                       \
        memcpy((char *)&temp[1], str, (len));            \
        OSAL_MboxPost(COMP_NB, 0, temp, (len + 1));      \
        OSAL_Free(temp);                                 \
    })

typedef void (*NB_TASK_response_callback)(uint8_t *, uint16_t);

static uint8_t NB_TASK_get_nb_status(void);
static uint8_t NB_TASK_receive_ble_convert_data_handle(uint8_t *pData, uint8_t dataLen);
#endif /* __NB_COMP_H__ */
